package com.dly.hope.service.impl;

import com.dly.hope.constant.ExceptionConstant;
import com.dly.hope.controller.ChatController;
import com.dly.hope.dao.WebSocketMessageDao;
import com.dly.hope.dto.WebSocketMessageDto;
import com.dly.hope.model.ro.ChatListRo;
import com.dly.hope.modle.Friend;
import com.dly.hope.modle.Session;
import com.dly.hope.modle.UserAccount;
import com.dly.hope.modle.WebSocketMessage;
import com.dly.hope.repository.*;
import com.dly.hope.service.ChatService;
import com.dly.hope.type.DataStatusEnum;
import com.dly.hope.type.SessionType;
import com.dly.hope.utils.ExceptionPropertiesUtil;
import com.dly.hope.vo.SessionVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ChatServiceImpl implements ChatService {

    @Resource
    private SessionRepository sessionRepository;

    @Resource
    private FriendRepository friendRepository;

    @Resource
    private UserAccountRepository userAccountRepository;

    @Resource
    private GroupRepository groupRepository;

    @Resource
    private WebSocketMessageDao webSocketMessageDao;

    @Resource
    private WebSocketMemberMessageRepository webSocketMemberMessageRepository;


    @Override
    public List<SessionVo> getSessionVo(String userId) {
        List<String> userSessionIds = new ArrayList<>();
        List<String> groupSessionIds = new ArrayList<>();

        //用来排序
        HashMap<String, Date> dateHashMap = new HashMap<>();

        sessionRepository.findAllByUserIdAndDataStatus(userId, DataStatusEnum.EFFICIENT.getCode())
                .forEach(session -> {
                    if (session.getSessionType().equals(SessionType.ALONG)) {
                        userSessionIds.add(session.getSessionId());
                    } else {
                        groupSessionIds.add(session.getSessionId());
                    }
                    dateHashMap.put(session.getSessionId(), session.getCreateDate());
                });

        ArrayList<SessionVo> sessionVos = new ArrayList<>();

        //好友关系
        Map<String, Friend> friendIdMap = friendRepository.findAllByUserIdAndIsAgreeAndDataStatus(userId, 1, 1).stream().collect(Collectors.toMap(
                Friend::getFriendId,
                friend -> friend,
                (old, now) -> now
        ));

        userAccountRepository.
                findAllByIdInAndDataStatus(userSessionIds, DataStatusEnum.EFFICIENT.getCode())
                .forEach(userAccount -> {
                    SessionVo sessionVo = new SessionVo();

                    sessionVo.setSessionId(userAccount.getId());
                    sessionVo.setAvatar(userAccount.getAvatar());
                    sessionVo.setSessionType(SessionType.ALONG);
                    sessionVo.setName(userAccount.getAccountName());
                    sessionVo.setNoReadNumber(webSocketMessageDao.getNotRead(userAccount.getId(), userId));
                    if(friendIdMap.get(userAccount.getId())==null){
                        sessionVo.setIsAdd(0);
                    }
                    sessionVos.add(sessionVo);
                });

        groupRepository.findAllByIdInAndDataStatus(groupSessionIds, DataStatusEnum.EFFICIENT.getCode())
                .forEach(group -> {
                    SessionVo sessionVo = new SessionVo();

                    sessionVo.setSessionType(SessionType.GROUP);
                    sessionVo.setSessionId(group.getId());
                    sessionVo.setAvatar(group.getAvatar());
                    sessionVo.setName(group.getName());
                    sessionVo.setNoReadNumber(webSocketMemberMessageRepository.findAllByGroupIdAndAcceptIdAndIsRead(group.getId(), userId, false).size());
                    sessionVos.add(sessionVo);
                });

        sessionVos.sort((a1, a2)->{
            //前一个的时间
            Date date1 = dateHashMap.get(a1.getSessionId());
            Date date2 = dateHashMap.get(a2.getSessionId());

            if(date2.before(date1)){
                return -1;
            }
            return 1;
        });

        return sessionVos;
    }

    private SessionVo getUser(String userId) {
        return userAccountRepository.findByIdAndDataStatus(userId, 1)
                .map(userAccount -> {
                    SessionVo sessionVo = new SessionVo();
                    sessionVo.setSessionId(userAccount.getId());
                    sessionVo.setAvatar(userAccount.getAvatar());
                    sessionVo.setSessionType(SessionType.ALONG);
                    sessionVo.setName(userAccount.getAccountName());
                    return sessionVo;
                })
                .orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.USER_ACCOUNT_NULL));
    }

    private SessionVo getGroup(String acceptId) {
        return groupRepository.findByIdAndDataStatus(acceptId, 1).map(group -> {
            SessionVo sessionVo = new SessionVo();
            sessionVo.setSessionId(group.getId());
            sessionVo.setSessionType(SessionType.GROUP);
            sessionVo.setName(group.getName());
            sessionVo.setAvatar(group.getAvatar());
            return sessionVo;
        }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.GROUP_NULL));
    }

    @Override
    public List<WebSocketMessageDto> getChatList(String sendId, ChatListRo chatListRo) {
        //如果是个人信息
        if (chatListRo.getSessionType().equals(SessionType.ALONG)) {
            SessionVo sendUser = getUser(sendId);
            SessionVo acceptUser = getUser(chatListRo.getAcceptId());
            return webSocketMessageDao.getMessage(sendId, chatListRo.getAcceptId()).stream()
                    .map(webSocketMessage -> {
                        WebSocketMessageDto dto = new WebSocketMessageDto();

                        if (webSocketMessage.getSendId().equals(sendId)) {
                            dto.setSend(sendUser);
                        } else {
                            dto.setSend(acceptUser);
                        }

                        if (webSocketMessage.getAcceptId().equals(chatListRo.getAcceptId())) {
                            dto.setAccept(acceptUser);
                        } else {
                            dto.setAccept(sendUser);
                        }

                        dto.setCreateDate(webSocketMessage.getCreateDate());
                        dto.setMessage(webSocketMessage.getMessage());
                        dto.setMessageType(webSocketMessage.getMessageType());
                        return dto;
                    }).collect(Collectors.toList());
        } else {
            //如果是群组信息
            SessionVo groupVo = getGroup(chatListRo.getAcceptId());

            List<String> sendUserIds = webSocketMessageDao.getGroupMessage(chatListRo.getAcceptId()).stream().map(WebSocketMessage::getSendId).distinct().collect(Collectors.toList());
            Map<String, SessionVo> sendUser = userAccountRepository.findAllByIdInAndDataStatus(sendUserIds, 1).stream().map(userAccount -> {
                SessionVo sessionVo = new SessionVo();

                sessionVo.setSessionId(userAccount.getId());
                sessionVo.setAvatar(userAccount.getAvatar());
                sessionVo.setSessionType(SessionType.ALONG);
                sessionVo.setName(userAccount.getAccountName());
                return sessionVo;
            }).collect(Collectors.toMap(SessionVo::getSessionId, sessionVo -> sessionVo, (oldValue, newValue) -> newValue));

            return webSocketMessageDao.getGroupMessage(chatListRo.getAcceptId())
                    .stream()
                    .map(webSocketMessage -> {
                        WebSocketMessageDto dto = new WebSocketMessageDto();
                        dto.setAccept(groupVo);
                        dto.setSend(sendUser.get(webSocketMessage.getSendId()));

                        dto.setCreateDate(webSocketMessage.getCreateDate());
                        dto.setMessage(webSocketMessage.getMessage());
                        dto.setMessageType(webSocketMessage.getMessageType());
                        return dto;
                    }).collect(Collectors.toList());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setRead(ChatListRo chatListRo, String userId) {
        if(chatListRo.getSessionType().equals(SessionType.ALONG)){
            webSocketMessageDao.getMessage(chatListRo.getAcceptId(), userId).forEach(webSocketMessage -> {
                webSocketMessage.setIsRead(Boolean.TRUE);
            });
        }else{
            List<String> collect = webSocketMessageDao.getGroupMessage(chatListRo.getAcceptId()).stream().map(WebSocketMessage::getId).collect(Collectors.toList());
            webSocketMemberMessageRepository.findAllByWebSocketMessageIdInAndAcceptId(collect, userId).forEach(webSocketMemberMessage -> {
                webSocketMemberMessage.setIsRead(Boolean.TRUE);
            });
        }
    }

    @Override
    //这里加事务会变慢
    public SessionVo creatSession(ChatListRo chatListRo, String userId) {

        if(!sessionRepository.findTopByUserIdAndSessionIdAndDataStatus(userId, chatListRo.getAcceptId(), 1).isPresent()){
            Session session = new Session();
            session.setUserId(userId);
            session.setSessionId(chatListRo.getAcceptId());
            session.setSessionType(chatListRo.getSessionType());
            sessionRepository.saveAndFlush(session);
        }

        SessionVo sessionVo = new SessionVo();

        //判断关系
        if(chatListRo.getSessionType().equals(SessionType.ALONG)) {
            if(!friendRepository.findTopByUserIdAndFriendIdAndDataStatus(userId, chatListRo.getAcceptId(), 1).isPresent()){
                sessionVo.setIsAdd(0);
            }
        }

        if(chatListRo.getSessionType().equals(SessionType.ALONG)){
            return userAccountRepository.findByIdAndDataStatus(chatListRo.getAcceptId(), 1).map(userAccount -> {
                sessionVo.setSessionId(userAccount.getId());
                sessionVo.setAvatar(userAccount.getAvatar());
                sessionVo.setSessionType(SessionType.ALONG);
                sessionVo.setName(userAccount.getAccountName());
                sessionVo.setNoReadNumber(webSocketMessageDao.getNotRead(userAccount.getId(), userId));
                return sessionVo;
            }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.USER_ACCOUNT_NULL));

        }else{
            return groupRepository.findByIdAndDataStatus(chatListRo.getAcceptId(), 1).map(group -> {
                sessionVo.setSessionType(SessionType.GROUP);
                sessionVo.setSessionId(group.getId());
                sessionVo.setAvatar(group.getAvatar());
                sessionVo.setName(group.getName());
                sessionVo.setNoReadNumber(webSocketMemberMessageRepository.findAllByGroupIdAndAcceptIdAndIsRead(group.getId(), userId, false).size());

                return sessionVo;
            }).orElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.GROUP_NULL));
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSession(ChatListRo chatListRo, String userId) {
        sessionRepository.findTopByUserIdAndSessionIdAndDataStatus(userId, chatListRo.getAcceptId(),1).ifPresent(session -> {
            session.setDataStatus(0);
        });
    }

}
